package com.itheima.crm.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.itheima.crm.dao.BaseDao;

public class BaseDaoImpl<T> extends HibernateDaoSupport implements BaseDao<T> {

	private Class<T> clazz;

	// 需要做的是在父类的构造方法中获得子类继承父类上的参数化类型中的实际类型参数
	// 解决方法一: 提供构造方法:在构造方法中传入具体类型的Class
	/*public BaseDaoImpl(Class<T> clazz) {
		this.clazz = clazz;
	}*/
	
	/**
	 * 不想子类上有构造方法,必须在父类中提供无参构造,并在无参构造中获取具体类型的Class
	 * 具体类型的Class是参数类型中的实际类型参数
	 */
	// 解决方法二: 通过泛型的反射
	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		// 反射: 第一步获得Class
		Class<T> clazz1 = (Class<T>) this.getClass(); // 正在被调用的那个类的Class
		// 第二步获得参数化的类型type
		Type type = clazz1.getGenericSuperclass(); //参数化类型: BaseDaoImpl<User>
		// 第三步将type强转成参数化的类型
		ParameterizedType pType = (ParameterizedType) type;
		// 第四步通过参数化类型获得实际类型参数:得到的是一个数组?如Map<String,Integer>
		Type[] typeArgs = pType.getActualTypeArguments();
		// 第五步只取第一个实际参数即可
		this.clazz = (Class<T>) typeArgs[0];
	}
	
	@Override
	public void save(T t) {
		this.getHibernateTemplate().save(t);
	}

	@Override
	public void update(T t) {
		this.getHibernateTemplate().update(t);
	}

	@Override
	public void delete(T t) {
		this.getHibernateTemplate().delete(t);
	}

	@Override
	public T findById(Serializable id) {
		return this.getHibernateTemplate().get(clazz, id);
	}

	// 查询所有记录数
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findAll() {
		return (List<T>) this.getHibernateTemplate().find("from " + clazz.getSimpleName());
	}

	// 统计个数的方法
	@SuppressWarnings("unchecked")
	@Override
	public Integer findCount(DetachedCriteria detachedCriteria) {
		// 设置查询条件
		detachedCriteria.setProjection(Projections.rowCount());
		List<Long> list = (List<Long>) this.getHibernateTemplate().findByCriteria(detachedCriteria);
		if (list.size() > 0) {
			return list.get(0).intValue();
		}
		return null;
	}

	// 分页查询的方法
	@SuppressWarnings("unchecked")
	@Override
	public List<T> findByPage(DetachedCriteria detachedCriteria, Integer begin, Integer pageSize) {
		detachedCriteria.setProjection(null);
		return (List<T>) this.getHibernateTemplate().findByCriteria(detachedCriteria, begin, pageSize);
	}


}
